package com.jmb.api.core.http;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONWriter;
import com.jmb.api.common.constant.RequestConstant;
import com.jmb.api.common.exception.LeaseException;
import com.jmb.api.common.result.ResultCodeEnum;
import jakarta.annotation.PostConstruct;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Component
public class Request {
    @Autowired
    RequestFactory requestFactory;

    private static Request request;

    public static class SingleRestTemplate {
        private static final RestTemplate INSTANCE = new RestTemplate();
    }

    public static RestTemplate getInstance() {
        RestTemplate restTemplate = SingleRestTemplate.INSTANCE;
        restTemplate.setRequestFactory(request.requestFactory.HttpClient());
        restTemplate.setErrorHandler(errorHandler());
        return restTemplate;
    }

    @PostConstruct
    public void init() {
        request = this;
        request.requestFactory = this.requestFactory;
    }

    // 错误处理
    private static ResponseErrorHandler errorHandler(){
        return new ResponseErrorHandler() {
            @Override
            public boolean hasError(ClientHttpResponse response) throws IOException {
                return false;
            }

            @Override
            public void handleError(ClientHttpResponse response) throws IOException {

            }
        };
    }
    public static ResponseEntity get(String url, HashMap<String, String> headers,HashMap<String, String> params){
        RestTemplate rest = Request.getInstance();
        HttpHeaders defaultHeaders = getDefaultHeader();
        if (StringUtils.isEmpty(url)){
            throw new LeaseException(ResultCodeEnum.WEB_API_URL_NULL);
        }
        if (headers !=null){
            defaultHeaders.setAll(headers);
        }
        if (params == null){
            // 如果参数为空，直接访问接口
            return rest.exchange(url, HttpMethod.GET,  new HttpEntity<>(defaultHeaders), String.class);
        }
        // 如果参数不为空，在执行
        else {
            HashMap<String, Object> urlParamsWrapper = pathVariableParser(url, params);
             url = (String) urlParamsWrapper.get("url");
             params=(HashMap<String, String>) urlParamsWrapper.get("params");
             return rest.exchange(UriComponentsBuilder.fromHttpUrl(url).queryParams(hashMap2LinkedMultiValueMap(params)).toString(), HttpMethod.GET,  new HttpEntity<>(defaultHeaders), String.class);
        }

    }
    /**
     * post
     * @param url url
     * @param headers 求头
     * @param params 请求参数
     * @param data 请求data
     * @param json 请求json
     * @return 响应实体
     */
    public static ResponseEntity post(String url, HashMap<String, String> headers, HashMap<String, String> params,
                                      HashMap<String, String> data, String json)   {
        return notGetRequest(HttpMethod.POST, url, headers, params, data, json);
    }

    /**
     * put
     * @param url url
     * @param headers 求头
     * @param params 请求参数
     * @param data 请求data
     * @param json 请求json
     * @return 响应实体
     */
    public static ResponseEntity put(String url, HashMap<String, String> headers, HashMap<String, String> params,
                                     HashMap<String, String> data, String json)  {
        return notGetRequest(HttpMethod.PUT, url, headers, params, data, json);
    }

    /**
     * patch
     * @param url url
     * @param headers 求头
     * @param params 请求参数
     * @param data 请求data
     * @param json 请求json
     * @return 响应实体
     */
    public static ResponseEntity patch(String url, HashMap<String, String> headers, HashMap<String, String> params,
                                       HashMap<String, String> data, String json)  {
        return notGetRequest(HttpMethod.PATCH, url, headers, params, data, json);
    }

    /**
     * delete
     * @param url url
     * @param headers 求头
     * @param params 请求参数
     * @param data 请求data
     * @param json 请求json
     * @return 响应实体
     */
    public static ResponseEntity delete(String url, HashMap<String, String> headers, HashMap<String, String> params,
                                        HashMap<String, String> data, String json)  {
        return notGetRequest(HttpMethod.DELETE, url, headers, params, data, json);
    }


    /**
     * @param httpMethod 请求方式
     * @param url 请求地址
     * @param headers 请求头
     * @param params 请求参数
     * @param body 请求body
     * @param mediaType 请求body类型
     * @return 响应实体
     */
    public static ResponseEntity requestProString(HttpMethod httpMethod, String url, HashMap<String, String> headers,
                                            HashMap<String, String> params, String body, MediaType mediaType) {

        RestTemplate restTemplate = Request.getInstance();
        HttpHeaders httpHeaders = getDefaultHeader();

        if (StringUtils.isEmpty(url)) {
            throw new LeaseException(ResultCodeEnum.WEB_API_URL_NULL);
        }

        HashMap<String, Object> urlParamsWrapper = pathVariableParser(url, params);
        url = (String) urlParamsWrapper.get("url");
        params = (HashMap<String, String>) urlParamsWrapper.get("params");

        if (params != null && !params.isEmpty()) {
            UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url).queryParams(hashMap2LinkedMultiValueMap(params));
            url = builder.toUriString();
        }
        httpHeaders.setContentType(mediaType);
        if (headers != null) {
            httpHeaders.setAll(headers);
        }
        if (body != null && !body.isEmpty()) {
            return restTemplate.exchange(url, httpMethod, new HttpEntity(body, httpHeaders), String.class);
        } else {
            return restTemplate.exchange(url, httpMethod, new HttpEntity(httpHeaders), String.class);
        }
    }

    /**
     * @param httpMethod 请求方式
     * @param url 请求地址
     * @param headers 请求头
     * @param params 请求参数
     * @param body 请求body
     * @param mediaType 请求body类型
     * @return 响应实体
     */
    public static ResponseEntity requestProHashMap(HttpMethod httpMethod, String url, HashMap<String, String> headers,
                                            HashMap<String, String> params, HashMap<String, String> body, MediaType mediaType)
            {

        RestTemplate restTemplate = Request.getInstance();
        HttpHeaders httpHeaders = getDefaultHeader();

        if (StringUtils.isEmpty(url)) {
            throw new LeaseException(ResultCodeEnum.WEB_API_URL_NULL);
        }

        HashMap<String, Object> urlParamsWrapper = pathVariableParser(url, params);
        url = (String) urlParamsWrapper.get("url");
        params = (HashMap<String, String>) urlParamsWrapper.get("params");

        if (params != null && !params.isEmpty()) {
            UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url).queryParams(hashMap2LinkedMultiValueMap(params));
            url = builder.toUriString();
        }
        httpHeaders.setContentType(mediaType);
        if (headers != null) {
            httpHeaders.setAll(headers);
        }
        if (body != null && !body.isEmpty()) {
            LinkedMultiValueMap<String, String> form = hashMap2LinkedMultiValueMap(body);
            return restTemplate.exchange(url, httpMethod, new HttpEntity(form, httpHeaders), String.class);
        } else {
            return restTemplate.exchange(url, httpMethod, new HttpEntity(httpHeaders), String.class);
        }
    }
    /**
     * @param httpMethod 请求方式
     * @param url 请求地址
     * @param headers 请求头
     * @param params 请求参数
     * @param mediaType 请求body类型
     * @return 响应实体
     */
    public static ResponseEntity requestProNotBody(HttpMethod httpMethod, String url, HashMap<String, String> headers,
                                            HashMap<String, String> params, MediaType mediaType)
             {

        RestTemplate restTemplate = Request.getInstance();
        HttpHeaders httpHeaders = getDefaultHeader();

        if (StringUtils.isEmpty(url)) {
            throw new LeaseException(ResultCodeEnum.WEB_API_URL_NULL);
        }

        if (params != null && !params.isEmpty()) {
            UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url).queryParams(hashMap2LinkedMultiValueMap(params));
            url = builder.toUriString();
        }
        httpHeaders.setContentType(mediaType);
        if (headers != null) {
            httpHeaders.setAll(headers);
        }
        return restTemplate.exchange(url, httpMethod, new HttpEntity(httpHeaders), String.class);
    }

    /**
     * @param httpMethod 请求方式
     * @param url 请求地址
     * @param headers 请求头
     * @param params 请求参数
     * @param body 请求body
     * @param mediaType 请求body类型
     * @return 响应实体
     */
    public static ResponseEntity requestPro(HttpMethod httpMethod, String url, HashMap<String, String> headers,
                                            HashMap<String, String> params, String body, MediaType mediaType)
             {

        RestTemplate restTemplate = Request.getInstance();
        HttpHeaders httpHeaders = getDefaultHeader();

        if (StringUtils.isEmpty(url)) {
            throw new LeaseException(ResultCodeEnum.WEB_API_URL_NULL);
        }

        HashMap<String, Object> urlParamsWrapper = pathVariableParser(url, params);
        url = (String) urlParamsWrapper.get("url");
        params = (HashMap<String, String>) urlParamsWrapper.get("params");

        if (params != null && !params.isEmpty()) {
            UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url).queryParams(hashMap2LinkedMultiValueMap(params));
            url = builder.toUriString();
        }
        httpHeaders.setContentType(mediaType);
        if (headers != null) {
            httpHeaders.setAll(headers);
        }
        if (body != null && !body.isEmpty()) {
            return restTemplate.exchange(url, httpMethod, new HttpEntity(body, httpHeaders), String.class);
        } else {
            return restTemplate.exchange(url, httpMethod, new HttpEntity(httpHeaders), String.class);
        }
    }

    /**
     * @param httpMethod 请求方式
     * @param url 请求地址
     * @param headers 请求头
     * @param params 请求参数
     * @param body 请求body
     * @param mediaType 请求body类型
     * @return 响应实体
     *
     */
    public static ResponseEntity requestPro(HttpMethod httpMethod, String url, HashMap<String, String> headers,
                                            HashMap<String, String> params, HashMap<String, String> body, MediaType mediaType) {

        RestTemplate restTemplate = Request.getInstance();
        HttpHeaders httpHeaders = getDefaultHeader();

        if (StringUtils.isEmpty(url)) {
            throw new LeaseException(ResultCodeEnum.WEB_API_URL_NULL);
        }

        HashMap<String, Object> urlParamsWrapper = pathVariableParser(url, params);
        url = (String) urlParamsWrapper.get("url");
        params = (HashMap<String, String>) urlParamsWrapper.get("params");

        if (params != null && !params.isEmpty()) {
            UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url).queryParams(hashMap2LinkedMultiValueMap(params));
            url = builder.toUriString();
        }
        httpHeaders.setContentType(mediaType);
        if (headers != null) {
            httpHeaders.setAll(headers);
        }
        if (body != null && !body.isEmpty()) {
            LinkedMultiValueMap<String, String> form = hashMap2LinkedMultiValueMap(body);
            return restTemplate.exchange(url, httpMethod, new HttpEntity(form, httpHeaders), String.class);
        } else {
            return restTemplate.exchange(url, httpMethod, new HttpEntity(httpHeaders), String.class);
        }
    }
    public static ResponseEntity requestPro(HttpMethod httpMethod, String url, HashMap<String, String> headers,
                                            HashMap<String, String> params, MediaType mediaType)
             {

        RestTemplate restTemplate = Request.getInstance();
        HttpHeaders httpHeaders = getDefaultHeader();

        if (StringUtils.isEmpty(url)) {
            throw new LeaseException(ResultCodeEnum.WEB_API_URL_NULL);
        }

        if (params != null && !params.isEmpty()) {
            UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url).queryParams(hashMap2LinkedMultiValueMap(params));
            url = builder.toUriString();
        }
        httpHeaders.setContentType(mediaType);
        if (headers != null) {
            httpHeaders.setAll(headers);
        }
        return restTemplate.exchange(url, httpMethod, new HttpEntity(httpHeaders), String.class);
    }




    private static ResponseEntity notGetRequest(HttpMethod httpMethod, String url, HashMap<String, String> headers,
                                                HashMap<String, String> params, HashMap<String, String> data, String json) {
        RestTemplate instance = Request.getInstance();
        HttpHeaders defaultHeader = getDefaultHeader();
        if (StringUtils.isEmpty(url)){
            throw new LeaseException(ResultCodeEnum.WEB_API_URL_NULL);
        }
        if (headers !=null){
            defaultHeader.setAll(headers);
        }
        if (StringUtils.isNoneEmpty(json) && data!=null){
            throw new LeaseException(ResultCodeEnum.WEB_API_DATA_JSON_NULL);
        }
        HashMap<String, Object> urlParamsWrapper = pathVariableParser(url, params);
        url = (String) urlParamsWrapper.get("url");
        params=(HashMap<String, String>) urlParamsWrapper.get("params");
        if (params != null && !params.isEmpty()) {
            UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url).queryParams(hashMap2LinkedMultiValueMap(params));
            url = builder.toUriString();
        }
        if (data != null) {
            LinkedMultiValueMap<String, String> formData = hashMap2LinkedMultiValueMap(data);
            defaultHeader.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
            return instance.exchange(url, httpMethod, new HttpEntity(formData, defaultHeader), String.class);
        } else {
            defaultHeader.setContentType(MediaType.APPLICATION_JSON);
            return instance.exchange(url, httpMethod, new HttpEntity(json, defaultHeader), String.class);
        }
    }


    /**
     * 获取响应状态码
     * @param response 响应实体
     * @return http响应头
     */
    public static Integer code (ResponseEntity response){
        return response.getStatusCode().value();
    }

    /**
     * 获取http响应body正文
     * @param response 响应实体
     * @return http相应正文
     */
    public static String body(ResponseEntity response){
        if (response.getBody() == null){
            return "";
        }else {
            return response.getBody().toString();
        }
    }
    /**
     * 获取http响应头
     * @param response 响应实体
     * @return http响应头
     */
    public static String headers(ResponseEntity response){
        return JSON.toJSONString(response.getHeaders());
    }
    /**
     * 获取http响应头 格式化
     * @param response 响应实体
     * @return http响应头
     */
    public static String headersPretty(ResponseEntity response){
        return JSON.toJSONString(response.getHeaders(), JSONWriter.Feature.PrettyFormat);
    }

    /**
     * 获取响应头 JSON包装
     * @param response 响应实体
     * @return http响应头
     */
    public static JSONObject headerJson(ResponseEntity response){
        return JSONObject.parseObject(JSONObject.toJSONString(response.getHeaders()));
    }


    /**
     * 请求工具类，解析url参数
     * @param url 请求地址
     * @param params 请求参数
     * @return HashMap<String, Object>
     */
    public static HashMap<String, Object> pathVariableParser(String url,HashMap<String,String> params){
        Pattern compile = Pattern.compile(RequestConstant.DEFAULT_PATTERN);
        Matcher matcher = compile.matcher(url);
        HashMap<String, Object> map = new HashMap<>();
        while (matcher.find()) {
            String pathVariable = matcher.group();
            String key = pathVariable.substring(1, pathVariable.length() - 1);
            if (params == null || params.isEmpty()) {
                throw new LeaseException(ResultCodeEnum.WEB_API_URL_PARAMS_NULL);
            }
            if (!params.containsKey(key)) {
                throw new LeaseException (ResultCodeEnum.WEB_API_URL_PARAMS_ERROR);
            } else {
                // 替换路径变量移除参数
                url = url.replace(pathVariable, params.remove(pathVariable.substring(1, pathVariable.length() - 1)));
            }
        }
        map.put("url", url);
        map.put("params", params);
        return map;

    }
    /**
     * 请求工具类，将HashMap转换为LinkedMultiValueMap
     * @param hashMap HashMap
     * @return LinkedMultiValueMap
     */
    private static <K,V> LinkedMultiValueMap hashMap2LinkedMultiValueMap(HashMap<K,V> hashMap){
        LinkedMultiValueMap<K,V> result = new LinkedMultiValueMap<>();
        if (hashMap==null){
            return null;
        }
        if (hashMap.isEmpty()){
            return result;
        }
        for (Map.Entry<K, V> entry : hashMap.entrySet()) {
            result.add(entry.getKey(),entry.getValue());
        }
        return result;
    }

    /**
     * 获取默认请求头
     * @return 返回http请求头
     */
    private static HttpHeaders getDefaultHeader(){
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.put("User-Agent", Arrays.asList(RequestConstant.DEFAULT_USER_AGENT));
        httpHeaders.put("Accept", Arrays.asList(RequestConstant.DEFAULT_ACCEPT));
        httpHeaders.put("Accept-Encoding", Arrays.asList(RequestConstant.DEFAULT_ACCEPT_ENCODING));
        httpHeaders.put("Accept-Language", Arrays.asList(RequestConstant.DEFAULT_ACCEPT_LANGUAGE));
        return httpHeaders;
    }

}
